
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml;

using Swaf;
using Swaf.Container;

namespace Swaf.BizObj
{
	public abstract class BaseBizObjList : IBizObjList, IBindingList, ITypedList, IDisposable, ICatalogItem 
	{
		protected IBizObjDefinition m_bizObjType = null;
		protected string m_listName = null;
		protected IBizObjSource m_source = null;

		//ICatalogItem Support
		protected string m_catalogName = null;
		protected string m_expiration = null;
		protected string m_key = null;
		protected string m_searchPath = null;

		public BaseBizObjList(string listName, IBizObjDefinition bizObjType)
		{
			m_bizObjType = bizObjType;
			m_listName = listName;
		}

		public BaseBizObjList(IBizObjSource src)
		{
			m_source = src;
		}

		public BaseBizObjList()
		{
		}

		public void setType(IBizObjDefinition bizObjType)
		{
			m_bizObjType = bizObjType;
		}
		#region IBizObjList Members

		public abstract IBizObj this[int index] { get;set;}
		public abstract IBizObj insertNew();
		public abstract int numElements {get;}
		public abstract IBizObj insertNewMakeCopy(IBizObj obj);
		public abstract void refresh();
		public abstract string getXml(string name, string decoInfo, bool setOnly, bool dirtyOnly, bool newOnly, bool getBasic, bool getObjs, bool getILists, bool getSysVals, XmlTextWriter xmlOut);
		public abstract string getXml(string name, bool setOnly, bool dirtyOnly, bool newOnly, bool getBasic, bool getObjs, bool getILists, bool getSysVals, XmlTextWriter xmlOut);
		public abstract void removeAt(int index);
		public abstract IBizObjCursor createCursor();
		public abstract IBizObj search(string fieldList, object matchValue);
		public abstract IBizObj search(string fieldList, object matchValue, bool findNearestMatch);

		public virtual IBizObjSource Source {get{return m_source;}}

		public virtual IKeyedBizObjList getIndex(string fieldList)
		{
			IBizObjList lst = this.Source.getList(this.objectType.Name, m_listName + ":" + fieldList);
			if(lst is IKeyedBizObjList)
				return (IKeyedBizObjList)lst;
			return null;
		}
		public virtual void refreshIndexesFromBizObj(IBizObj insertedObj)
		{
			//Nothing to do in the base.
		}

		public virtual IBizObjDefinition objectType
		{
			get
			{
				return m_bizObjType;
			}
		}


		public virtual string getXml(string options)
		{
			string name = this.Name;
			Regex regex = new Regex(@"name\((\w+)\)");
			Match m = regex.Match(options);
			if(m.Success)
				name = m.Value;
			else if((name == null || name == "") && this.objectType != null)
				name = this.objectType.Name + "s";

			regex = new Regex(@"deco\((\w+)\)");
			string decoInfo = "ExternalUntrusted";
			m = regex.Match(options);
			if (m.Success)
				decoInfo = m.Groups[1].Value;

			bool setOnly = (options.IndexOf("setOnly") != -1) ? true : false;
			bool dirtyOnly = (options.IndexOf("dirtyOnly") != - 1)?true:false;
			bool newOnly = (options.IndexOf("newOnly") != - 1)?true:false;
			bool getBasic = (options.IndexOf("basicProperties") != - 1)?true:false;
			bool getObjs = (options.IndexOf("objProperties") != - 1)?true:false;
			bool getILists = (options.IndexOf("listProperties") != - 1)?true:false;
			bool getSysVals = (options.IndexOf("sysProperties") != - 1)?true:false;
			
			if (options.IndexOf("public") == 0)
			{
				setOnly = BizObjManager.XmlOutSetOnly;;
				dirtyOnly = false;
				newOnly = false;
				getBasic = true;
				getObjs = true;
				getILists = true;
				getSysVals = false;
			}
			else if (options.IndexOf("all") == 0)
			{
				setOnly = false;
				dirtyOnly = false;
				newOnly = false;
				getBasic = true;
				getObjs = true;
				getILists = true;
				getSysVals = true;
			}

			return getXml(name, decoInfo, setOnly, dirtyOnly, newOnly, getBasic, getObjs, getILists, getSysVals, null);
		}
		public virtual string Xml 
		{
			get
			{
				return getXml("public");
			}
		}

		public string Name {get{return m_listName;}set{m_listName=value;}}

		#endregion

		#region INameAddressSupport
		public void put(string nameAddress, object val)
		{
			IBizObj el = (IBizObj)get(NameAddress.getFirstAddress(nameAddress));
			if (el != null)
				el.put(NameAddress.getRemainingAddress(nameAddress), val);
		}

		public void put(string nameAddress, object val, object extraInfo)
		{
			put(nameAddress, val);
		}

		public object get(string nameAddress, params object[] infoArgs)
		{
			if(Cmn.IsEmpty(nameAddress))
				return this;

			IBizObj item = null;
			string entry = NameAddress.getFirstAddress(nameAddress);
			bool createIfNotFound = false;
			if (entry.EndsWith("-C"))
			{
				entry = entry.Substring(0, entry.Length - 2);
				createIfNotFound = true;
			}
			string updateFldName = null;
			object updateFldVal = null;

			if(entry.Length > 0 && entry[0] == '[')
			{
				//Using an index to access the list
				int index = Int32.Parse(entry.Substring(1,entry.Length-2));
				item = this[index];
			}
			else if(entry.Length > 0 && entry[0] == '(')
			{
				//Using a specific field list to search for a specific value
				//such as (City,State:AtlantaGA) or (City:Atlanta)
				int p = entry.IndexOf(':');
				if(p != -1)
				{
					updateFldName = entry.Substring(1, p-1);
					updateFldVal = entry.Substring(p+1, entry.Length - p-2);
					item = this.search(updateFldName, updateFldVal);
				}
			}
			else if(entry != null)
			{
				//Doing a search of the key value
				updateFldName = objectType.KeyFieldNames;
				updateFldVal = objectType.convertValueToKeyType(entry);
				item = this.search(updateFldName, updateFldVal);
			}

			if (createIfNotFound && item == null)
			{
				item = Application.globalApp.bizObjMgr.create(m_bizObjType.Name);
				item.put(m_bizObjType.KeyFieldNames, updateFldVal);
				item.clearDirtyFlags();
				IKeyedBizObjList idIndex = this.getIndex(objectType.KeyFieldNames);
				idIndex.Add(item);
			}
			if (NameAddress.isSingleAddress(nameAddress))
				return item;
			else if (item != null)
				return item.get(NameAddress.getRemainingAddress(nameAddress), infoArgs);
			
			return null;
		}

		public object get(string nameAddress, object oneArg)
		{
			return this.get(nameAddress, new object[]{oneArg});
		}

		public object get(string nameAddress)
		{
			return this.get(nameAddress, (object[])null);
		}

		public bool isGetOnly{get{return false;}}
		public XmlSerializationSupport SerializationSupport {get{return XmlSerializationSupport.AsElement;}}
		public bool containsField(String nameAddress)
		{
			return false;
		}
		#endregion

		#region ICloneable Members

		public abstract object Clone();

		#endregion

		#region IBindingList Members

		public virtual void AddIndex(PropertyDescriptor property) {throw new NotImplementedException();}
		public virtual bool AllowNew {get{return true;}}
		public virtual void ApplySort(PropertyDescriptor property, ListSortDirection direction) {throw new NotImplementedException();}
		public virtual PropertyDescriptor SortProperty {get{return null;}}
		public virtual int Find(PropertyDescriptor property, object key) {throw new NotImplementedException();}
		public virtual bool SupportsSorting {get{return false;}}
		public virtual bool IsSorted {get{return false;}}
		public virtual bool AllowRemove {get{return true;}}
		public virtual bool SupportsSearching {get{return false;}}
		public virtual ListSortDirection SortDirection {get{return new ListSortDirection();}}
		public virtual event ListChangedEventHandler ListChanged;
		public virtual bool SupportsChangeNotification {get{return false;}}
		public virtual void RemoveSort() {throw new NotImplementedException();}
        public virtual void Remove(object value) { throw new NotImplementedException(); }
        public virtual object AddNew() { return insertNew(); }
		public virtual bool AllowEdit {get{return true;}}
		public void RemoveIndex(PropertyDescriptor property) {throw new NotImplementedException();}
		#endregion

		#region IList Members

		public bool IsReadOnly {get{return false;}}

		object IList.this[int index]
		{
			get
			{
				return ((IBizObjList)this)[index];
			}
			set
			{
				// TODO:  Add BaseBizObjList.System.Collections.IList.this setter implementation
			}
		}

		public void RemoveAt(int index)
		{
			removeAt(index);
		}

		public virtual void Insert(int index, object value)
		{
			// TODO:  Add BaseBizObjList.Insert implementation
		}


		public bool Contains(object value)
		{
			// TODO:  Add BaseBizObjList.Contains implementation
			return false;
		}

//		public void Clear()
//		{
//			// TODO:  Add BaseBizObjList.Clear implementation
//			
//		}

		public abstract void Clear();
		public virtual int IndexOf(object value)
		{
			// TODO:  Add BaseBizObjList.IndexOf implementation
			return 0;
		}

		virtual public int Add(object value)
		{
			// TODO:  Add BaseBizObjList.Add implementation
			return 0;
		}

		public bool IsFixedSize
		{
			get
			{
				// TODO:  Add BaseBizObjList.IsFixedSize getter implementation
				return false;
			}
		}

		#endregion

		#region ICollection Members

		public bool IsSynchronized {get{return false;}}

		public int Count {get{return numElements;}}

		public void CopyTo(Array array, int index)
		{
			// TODO:  Add BaseBizObjList.CopyTo implementation
		}

		public object SyncRoot
		{
			get
			{
				// TODO:  Add BaseBizObjList.SyncRoot getter implementation
				return null;
			}
		}

		#endregion

		#region IEnumerable Members

		public IEnumerator GetEnumerator()
		{
			// TODO:  Add BaseBizObjList.GetEnumerator implementation
			return  new BizObjListEnumerator(this);
		}

		#endregion

		#region ITypedList Members

		public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
		{
			IBizObjDefinition bizType = objectType;
			if(listAccessors != null && listAccessors.Length >0)
			{
				BizObjPropertyDescriptor bp = (BizObjPropertyDescriptor)listAccessors[0];
				if(bp.Field.BizType == BizFieldType.BizObjList)
					bizType = ((IBizObjList)bp.Field.SampleValue).objectType;
			}

			//return TypeDescriptor.GetProperties(this, attributes, true);
			int numFields = 0;
			foreach(BizObjField field in bizType.Fields.Values)
			{
				if(field.BizType == BizFieldType.BizObj)
				{
					foreach (BizObjField childField in ((IBizObj)field.SampleValue).type.Fields.Values)
					{
						++numFields;
					}
				}
				else
					++numFields;
			}

			PropertyDescriptor[] propArray = new PropertyDescriptor[numFields];
			int pos = 0;
			foreach (BizObjField field in bizType.Fields.Values)
			{
				if(field.BizType == BizFieldType.BizObj)
				{
					IBizObjDefinition childType = ((IBizObj)field.SampleValue).type;
					foreach (BizObjField childField in childType.Fields.Values)
					{
						propArray[pos++] = new BizObjPropertyDescriptor(childField, childType, field.Name + "." + childField.Name);
					}
				}
				else
					propArray[pos++] = new BizObjPropertyDescriptor(field, bizType);
			}
			return new PropertyDescriptorCollection(propArray);
		}

		public string GetListName(PropertyDescriptor[] listAccessors)
		{
			if(listAccessors != null && listAccessors.Length > 0)
			{
				BizObjPropertyDescriptor bp = (BizObjPropertyDescriptor)listAccessors[0];
				if(bp.Field.BizType == BizFieldType.BizObjList)
					return ((IBizObjList)bp.Field.SampleValue).objectType.Name;
				else
					return objectType.Name;
			}
			else
				return objectType.Name;
		}

		#endregion

		#region IDisposable Members

		public void Dispose()
		{
			cleanUp();
			GC.SuppressFinalize(this);
		}
		private void cleanUp()
		{
			Clear();
			if(Source != null)
				Source.RemoveList(this.Name);
		}
		~ BaseBizObjList()
		{
			cleanUp();
		}
		#endregion

		#region ICatalogItem Members
		public string catalogName
		{
			get	{return m_catalogName;}
			set	{m_catalogName = value;}
		}

		public string key
		{
			get	{return m_key;}
			set	{m_key = value;}
		}

		public string expiration
		{
			get	{return m_expiration;}
			set	{m_expiration = value;}
		}

		public string searchPath
		{
			get	{return m_searchPath;}
			set {m_searchPath = value;}
		}

		public bool isCacheable
		{
			get { return true; }
		}

		#endregion

    }

    public class BizObjListEnumerator : IEnumerator
	{
		IBizObjList m_interalList;
		int m_currentIndex = -1;
		#region IEnumerator Members
		public BizObjListEnumerator(IBizObjList list)
		{
			m_interalList = list;	
			m_currentIndex = -1;
		}

		public void Reset()
		{
			m_currentIndex = -1;
		}

		public object Current
		{
			get
			{
				if (m_interalList.numElements > 0)
					return m_interalList[m_currentIndex];
				else
					return null;
			}
		}

		public bool MoveNext()
		{
			if (++m_currentIndex == m_interalList.numElements || m_interalList.numElements == 0)
			{
				m_currentIndex--;
				return false;
			}
			else
				return true;
		}

		#endregion

	}

}
